import { merge } from 'lodash'
import { I18nOptions, I18nService, I18nTranslation } from 'nestjs-i18n'
import * as path from 'path'
import { BehaviorSubject, Observable } from 'rxjs'
import * as format from 'string-format'
import { Logger } from '@nestjs/common'
import { I18nFileJsonLoader } from './loader/i18n-file-json.loader'

export class I18nFactory {
  protected static instance?: I18nService

  protected static readonly options: I18nOptions = {
    fallbackLanguage: 'zh-cn',
    loaderOptions: {
      path: path.join(__dirname, '../resource/i18n/locale'),
      watch: false,
    },
    resolvers: [],
    logging: true,
    throwOnMissingKey: false,
    formatter: format,
  }

  static initInstance(options?: { i18nOptions?: Partial<I18nOptions>; logger?: Logger }) {
    if (this.instance) {
      return
    }

    const i18nOptions = merge({}, this.options, options?.i18nOptions)
    const i18nLanguagesSubject = new BehaviorSubject<string[]>([])
    const i18nTranslationSubject = new BehaviorSubject<I18nTranslation>({})
    const loader = new I18nFileJsonLoader(i18nOptions.loaderOptions)
    const translation = loader.parseTranslationsSync()
    if (translation instanceof Observable) {
      translation.subscribe(i18nTranslationSubject)
    } else {
      i18nTranslationSubject.next(translation)
    }

    const languages = loader.parseLanguagesSync()
    if (languages instanceof Observable) {
      languages.subscribe(i18nLanguagesSubject)
    } else {
      i18nLanguagesSubject.next(languages)
    }

    this.instance = new I18nService(
      i18nOptions,
      i18nTranslationSubject.asObservable(),
      i18nLanguagesSubject.asObservable(),
      options?.logger ?? new Logger(),
      loader,
      i18nLanguagesSubject,
      i18nTranslationSubject
    )
  }

  static getInstance() {
    if (!this.instance) {
      this.initInstance()
    }
    return this.instance
  }
}
